package inutan.gateway;

import inutan.common.inner.GameCodec;
import inutan.gateway.external.*;
import inutan.common.config.GatewayConfig;
import inutan.gateway.inner.InnerHandler;
import inutan.common.inner.protocol.InnerProtocol;
import org.ricks.boot.Ricks;
import org.ricks.common.ModularContext;
import org.ricks.common.lang.Logger;
import org.ricks.net.AioServer;
import org.ricks.net.DataCodecKit;
import org.ricks.net.buffer.BufferPagePool;
import org.ricks.net.transport.Worker;
import org.ricks.net.transport.kcp.KcpBootstrap;
import java.io.IOException;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @author chenwei
 * @Description:网关节点
 * 对外 和 对内 消息转发
 * 维护外部连接 和 内部连接
 * 网关即使client 入口，那就意味网络维护了所有指令
 * 然后根据指令分配不同的业务集群 以及 集群节点
 *
 * 业务 to 业务，实际还是经过网关，然后再根据指令转发给 交互服 或者 逻辑服
 *
 * 网关维护所有的指令，根本指令做路由转发
 *
 * 简单来吧，注册中心就用redis ，网关节点启动 。网关节点的 IP 端口 注册进redis 中，其它业务节点启动启动直接从redis 获取所有网关信息 ，进行连接
 *
 * 全局统一编码 解码
 *
 * 1.消息转发，不需要堆业务代码 直接自定义handler 约定cmd职责范围进行不同模块集群转发
 * 2.维护玩家session ，以及业务节点session
 * 3.检验登陆权限 以及访问权限
 * 4.kcp & tcp 同时使用，收到什么协议请求就以什么协议返回，就得做下处理
 * 5.luban协议整合进网关
 *
 * 2023年2月16日 15:46:33
 * 1.登录 重新登录  顶号 处理  ，使用内部字节流解析器进行测试
 * 2.玩家退出 缓存clear 异步db数据 优化 测试
 * 3、外部协议luban 整合进broker中，&测试&客户端调试  【完成】
 * 4、玩家连接断线重连测试
 * 5、聊天搭建
 * 6、match server 搭建 以及 mmo 逻辑开发 收到mmo 消息缓存下来，然后以固定频率 广播房间其它成员 [50ms ? 广播频率待确认]
 * 7.策划表 生成data 机制调整
 * 8.class data 热更优化测试
 *
 * 内部协议基本完成制定
 */
public class GatewayRun {

    public static void main(String[] args)  {
        ModularContext.me().scan(Set.of("inutan.gateway","inutan.common.inner.protocol",
                "inutan.game","inutan.match.action"));
        Ricks.run(GatewayBootstrap.class, args);
        DataCodecKit.setDataCodec(new GameCodec());
        startExternalServer(); //启动对外服务
        startInnerServer(); //启动对内服务
    }

    /**
     * 启动对外服务
     */
    private static void startExternalServer() {
        try {
            BufferPagePool bufferPagePool = new BufferPagePool(1024 * 1024 * 16, Runtime.getRuntime().availableProcessors() + 1, true);
            Worker worker = new Worker(bufferPagePool, Runtime.getRuntime().availableProcessors());

            GameHeartPlugin gameHeartPlugin = new GameHeartPlugin(1,300,TimeUnit.SECONDS,new HeartTimeoutCallback());//5分钟心跳超时
            ExternalHandler externalHandler = new ExternalHandler();
            externalHandler.addPlugin(gameHeartPlugin); //5分钟
            AioServer server = new AioServer(GatewayConfig.BROKER_EXTERNAL_PORT, new ExternalProtocol(),externalHandler);
            KcpBootstrap bootstrap = new KcpBootstrap(new KcpExternalProtocol(),externalHandler,worker);
//            kcpServer.setThreadNum(17);
//            kcpServer.setReadBufferSize(1024*2048);
//            kcpServer.setBufferPagePool(bufferPagePool);
            server.start();
            bootstrap.setThreadNum(Runtime.getRuntime().availableProcessors())
                    .setBufferPagePool(bufferPagePool)
                    .setReadBufferSize(1024 * 2048).open(GatewayConfig.BROKER_EXTERNAL_PORT);

//            kcpServer.open(GatewayConfig.BROKER_EXTERNAL_PORT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 启动对内服务
     */
    private static void startInnerServer() {
        long startTime = System.currentTimeMillis();
        InnerProtocol protocol = new InnerProtocol();
        InnerHandler handler = new InnerHandler();
        AioServer aioServer = new AioServer(GatewayConfig.BROKER_INNER_PORT, protocol,handler);
        try {
            aioServer.start();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            long endTime = System.currentTimeMillis();
            Logger.info("starting gateway inner server cost time:" + (endTime - startTime) + "ms");
        }
    }
}
